﻿using System.Collections.Concurrent;
using System.Linq.Expressions;

namespace GoodAdmin.System;

/// <inheritdoc cref="ISysUserService"/> 
public class SysUserService:DbRepository<SysUser>, ISysUserService, ITransient
{
    private readonly IConfigService _configService;
    private readonly IRedisCacheManager _redisManager;
    private readonly IRelationService _relationService;
    private readonly ISysRoleService _roleService;
    private readonly IMenuService _menuService;
    private readonly ISysOrgService _orgService;

    public SysUserService( IConfigService configService, IRedisCacheManager redisManager, 
        IRelationService relationService, ISysRoleService roleService,
        IMenuService menuService,ISysOrgService orgService)
	{
        _configService = configService;
        _redisManager = redisManager;
        _relationService = relationService;
        _roleService = roleService;
        _menuService = menuService;
        _orgService = orgService;
    }

    /// <inheritdoc/>
    public async Task AddUser(UserAddInput userInput)
    {
        await CheckInput(userInput);

        //设置默认密码
        var pwd= await GetDefaultPassword();
        userInput.Password = pwd;
        //插入时忽略系统标识字段
        await Context.Insertable<SysUser>(userInput)
            .IgnoreColumns(u=>new { u.SystemMark }).ExecuteCommandAsync();
    }

    /// <inheritdoc/>
    public async Task<List<UserBatchAddOutput>> BatchAddUser(List<UserBatchAdd> importData)
    {
        var (userList, errorList) = await CheckImportData(importData);
        if (userList.Count > 0)
        {
            var res = await Context.Ado.UseTranAsync(async () =>
            {
                await DbContext.Db.Fastest<SysUser>().PageSize(100000).BulkCopyAsync(userList);
            });
            //如果插入失败，那么数据存到errorList，并返回给前端
            if (!res.IsSuccess)
            {
                foreach (var item in userList)
                {
                    var errorItem = item.Adapt<UserBatchAddOutput>();
                    errorItem.ErrorMessages = "插入数据库失败";
                    errorList.Add(errorItem);
                }
            }
        }
        return errorList;
    }

    /// <inheritdoc/>
    public async Task UpdateUser(UserUpdateInput userInput)
    {
        await CheckInput(userInput);
        var user= await GetUserById(userInput.Id);
        var res = await Context.Updateable<SysUser> (userInput)
            .IgnoreColumns(u => new { u.SystemMark, u.Password, u.Status }).ExecuteCommandAsync();
        if (res > 0)
        {
            //删除用户缓存
            DeleteUserCache(userInput.Id);
            //如果变更了组织，那么也需要移除当前的数据范围
            if (user.OrgId != userInput.OrgId)
            {
                RemoveApiRoleCache(userInput.Id);
            }
        }
            
    }

    /// <inheritdoc/>
    public async Task DeleteUser(List<BaseIdInput> Input)
    {
        var ids = Input.Select(x => x.Id).ToList();
        if (ids.Count == 0) return;
        //不能删除自己
        if (ids.Contains(UserManager.UserId))
            throw Oops.Bah(UserErrorCode.U003);

        var userList = await GetListAsync(u => ids.Contains(u.Id));
        //不能删除系统自带超级管理员
        if(userList.Any(u=> u.Account==RoleConst.SUPERADMIN &&ids.Contains(u.Id)))
        {
            throw Oops.Bah(UserErrorCode.U002);
        }
        
        await DeleteByIdsAsync(ids.Cast<dynamic>().ToArray());
        //删除用户缓存
        DeleteUserCache(ids);
    }

    /// <inheritdoc/>
    public async Task<bool> DisableUser(BaseIdInput input)
    {
        var user = await GetUserById(input.Id);        
        if (user.Account == RoleConst.SUPERADMIN)
        {
            throw Oops.Bah(UserErrorCode.U004);
        }
        if (input.Id == UserManager.UserId)
        {
            throw Oops.Bah(UserErrorCode.U005);
        }

        var res = await UpdateAsync(u => new SysUser { Status = CommonConst.STATUS_DISABLE }, u => u.Id == input.Id);
        if (res)
        {
            DeleteUserCache(input.Id);
        }
        return res;   
    }

    /// <inheritdoc/>
    public async Task<bool> EnableUser(BaseIdInput input)
    {
        var res = await UpdateAsync(u => new SysUser { Status = CommonConst.STATUS_ENABLE }, u => u.Id == input.Id);
        if (res)
        {
            DeleteUserCache(input.Id);
        }
        return res;
    }

    /// <inheritdoc/>
    public async Task<SqlSugarPagedList<SysUser>> GetUserPage(UserPageInput input)
    {       
        return await Context.Queryable<SysUser>()
            .LeftJoin<SysOrg>((u,o)=>u.OrgId==o.Id)
            //.LeftJoin<SysPosition>((u,o,p)=>u.PositionId==p.Id)
            .WhereIF(input.Expression!=null,input.Expression?.ToExpression())
            .WhereIF(input.OrgId>0, u => u.OrgId == input.OrgId)
            .WhereIF(!string.IsNullOrWhiteSpace(input.Gender), u => u.Gender == input.Gender)
            .WhereIF(!string.IsNullOrWhiteSpace(input.Status), u => u.Status == input.Status)
            .WhereIF(!string.IsNullOrWhiteSpace(input.Name), u => u.Name.Contains(input.Name))
            //.Select((u,o,p)=>new SysUser { Id=u.Id.SelectAll(),OrgName=o.OrgName,PosName=p.Name})
            .Select((u, o) => new SysUser { Id = u.Id.SelectAll(), OrgName = o.OrgName})
            .Mapper(u => u.Password=null)
            .ToPagedListAsync(input.PageIndex, input.PageSize);
    }

    /// <inheritdoc/>
    public async Task<SysUser> GetUserById(long userId)
    {
        var user = _redisManager.HashGet<SysUser>(CacheConst.SysUser, userId.ToString() )[0];
        if (user == null)
        {
            user = await GetFirstAsync(u => u.Id == userId);
            if(user!=null)
                _redisManager.HashSet(CacheConst.SysUser, userId.ToString(), user);
        }        
        return user;
    }

    public async Task<SqlSugarPagedList<UserSimpleInfo>> UserSelector(UserSelectorInput input)
    {
        var users = await Context.Queryable<SysUser>().WhereIF(input.OrgId > 0, it => it.OrgId == input.OrgId)
            .WhereIF(!string.IsNullOrWhiteSpace(input.keyword), it => it.Name.Contains(input.keyword) || it.Account.Contains(input.keyword))
            .Select<UserSimpleInfo>()
            .ToPagedListAsync(input.PageIndex, input.PageSize);
        return users;
    }

    /// <inheritdoc/>
    public async Task<UserOutput> GetLoginUserDetail()
    {
        var user = await GetUserById(UserManager.UserId);
        var userOutput=user.Adapt<UserOutput>();
        return userOutput;
    }
    /// <inheritdoc/>
    public async Task<dynamic> GetLoginUserMenuAndButton()
    {
        var menuList = await GetUserRoleMenu();
        var buttons = menuList.Where(it => it.MenuType == CommonConst.MENUTYPE_BUTTON).Select(it => it.Path).ToList();
        var menus = menuList.Where(it => it.MenuType != CommonConst.MENUTYPE_BUTTON).ToList();
        //构造成树形结构
        menus = UtilMethod.ConstructTree(menus);
        dynamic res = new
        {
            Buttons = buttons,
            MenuList = menus
        };        
        return res;
    }
    /// <inheritdoc/>
    public async Task<SysUser> GetUserByAccount(string Account)
    {
        var user = await GetFirstAsync(it => it.Account == Account);
        if (user != null)
            _redisManager.HashSet(CacheConst.SysUser, user.Id.ToString(), user);
        return user;
    }   

    public async Task<List<UserSelectorOutput>> GetUserSelector(UserSelectorInput input, List<long> dataScope, bool isCheckDataScope)
    {
        List<UserSelectorOutput> userSelectors = new();
        //如果需要检查权限，且数据范围没有数据，那么就查询自己
        if(isCheckDataScope && dataScope.Count == 0)
        {
            userSelectors= await DbContext.Db.Queryable<SysUser>().Where(it=>it.Id==UserManager.UserId)
                .WhereIF(!string.IsNullOrWhiteSpace(input.keyword), it => it.Name.Contains(input.keyword) || it.WorkId.Contains(input.keyword))
                .WhereIF(input.OrgId > 0, it => it.OrgId == input.OrgId)
                .Select(it => new UserSelectorOutput
                {
                    Id = it.Id,
                    Name = $"{it.Name}/{it.WorkId}",
                    IsLeaf = true,
                    Type = CommonConst.USER,
                    Icon = "ele-User"
                }
                ).ToListAsync();
        }
        //如果有输入关键字查询，那么以这个为优先查询条件,查询用户
        else if (!string.IsNullOrWhiteSpace(input.keyword))
        {
            userSelectors = await DbContext.Db.Queryable<SysUser>()
                .WhereIF(isCheckDataScope && dataScope.Count > 0, it => dataScope.Contains(it.OrgId))
                .WhereIF(!string.IsNullOrWhiteSpace(input.keyword),it => it.Name.Contains(input.keyword) || it.WorkId.Contains(input.keyword))
                .WhereIF(input.OrgId>0,it=>it.OrgId==input.OrgId)
                .Select(it => new UserSelectorOutput
                {
                    Id = it.Id,
                    Name = $"{it.Name}/{it.WorkId}",
                    IsLeaf = true,
                    Type = CommonConst.USER,
                    Icon = "ele-User"
                }
                ).ToListAsync();
        }
        else
        {                        
            var orgList = await DbContext.Db.Queryable<SysOrg>()
                .Where(it=>it.ParentId==input.OrgId)
                .WhereIF(isCheckDataScope && dataScope.Count>0, it=>dataScope.Contains(it.Id))
                .Select(it => new UserSelectorOutput
                {
                    Id = it.Id,
                    Name = it.OrgName,
                    IsLeaf = false,
                    Type = it.Category,
                    Icon = "",
                    ParentId=it.ParentId,
                }).ToListAsync();
            userSelectors.AddRange(orgList);
            //如果部门id=0，那么就查询最上级部门
            if (input.OrgId > 0)
            {
                var userList = await DbContext.Db.Queryable<SysUser>()
                 .Where(it => it.OrgId == input.OrgId)
                 .WhereIF(isCheckDataScope && dataScope.Count > 0, it => dataScope.Contains(it.OrgId))
                 .Select(it => new UserSelectorOutput
                 {
                     Id = it.Id,
                     Name = $"{it.Name}/{it.WorkId??""}",
                     IsLeaf = true,
                     Type = CommonConst.USER,
                     Icon = "ele-User"
                 }
                 ).ToListAsync();
                userSelectors.AddRange(userList);
            }
        }
        return userSelectors;
    }

    /// <inheritdoc/>
    public async Task GrantUserRole(UserRoleInput input)
    {
        //不能为系统内置超级管理员赋予角色
        var user = await GetUserById(input.Id);
        if (user == null) return;
        
        if (user.Account == RoleConst.SUPERADMIN)
        {
            throw Oops.Bah(RoleErrorCode.R005);
        }
        var res = await Context.Ado.UseTranAsync(async () =>
        {
            await _relationService.DeleteRelationByCategoryAndTargetId(CategoryConst.RELATION_ROLE_USER, input.Id);
            await _relationService.AddRelationByTargetId(CategoryConst.RELATION_ROLE_USER, input.Id, input.RoleIdList);
        });
        //成功之后再刷新缓存
        if (res.IsSuccess)
        {
            DeleteUserCache(input.Id);
            //删除用户数据范围
            RemoveApiRoleCache(input.Id);
        }
    }

    /// <inheritdoc/>
    public async Task ResetPassword(BaseIdInput input)
    {
        var pwd = await GetDefaultPassword();
        if(await UpdateAsync(u => new SysUser { Password = pwd }, u => u.Id == input.Id))
        //删除用户缓存
            DeleteUserCache(input.Id);
    }

    /// <inheritdoc/>
    public async Task ChangePassword(ChangePwdInput input)
    {
        var passwordNew = CryptogramUtil.Sm2Encrypt(input.PasswordNew);
        if (await Context.Updateable<SysUser>().SetColumns(u => u.Password==passwordNew)
            .Where(u=>u.Id==input.Id).ExecuteCommandAsync()>0)
            DeleteUserCache(input.Id);
    }

    /// <inheritdoc/>
    public string UnLockUser(BaseIdInput input)
    {
        if (string.IsNullOrWhiteSpace(_redisManager.HashGet<string>(CacheConst.LockedUser, input.Id.ToString())[0]))
        {
            return "用户未锁定";
        }
        _redisManager.HashDel<string>(CacheConst.LockedUser, input.Id.ToString());
        _redisManager.HashDel<int>(CacheConst.UserLoginWrongNumber, input.Id.ToString());
        return "解锁成功";
    }

    /// <inheritdoc/>
    public async Task<string> GetDefaultPassword()
    {
        var defaultPwd =  (await _configService.GetConfigInfo(CategoryConst.SYS_CONFIG, ConfigConst.SYS_DEFAULT_PASSWORD)).ConfigValue;
        //使用sm2加密
        defaultPwd = CryptogramUtil.Sm2Encrypt(defaultPwd);
        return defaultPwd;
    }

    /// <inheritdoc/>
    
    public async Task<List<UserSimpleInfo>> GetUsersByField<T>(List<T> values, Expression<Func<SysUser, T>> fieldSelector)
    {
        if (values.Count == 0) return new List<UserSimpleInfo>();

        // 动态构建表达式树
        var parameter = Expression.Parameter(typeof(SysUser));
        var fieldAccess = Expression.Invoke(fieldSelector, parameter);
        var containsMethod = typeof(Enumerable).GetMethods()
            .First(m => m.Name == "Contains" && m.GetParameters().Length == 2)
            .MakeGenericMethod(typeof(T));
        var containsExpr = Expression.Call(containsMethod,
            Expression.Constant(values),
            fieldAccess);

        var predicate = Expression.Lambda<Func<SysUser, bool>>(containsExpr, parameter);

        // 统一映射字段
        return await GetFieldListAsync<SysUser, UserSimpleInfo>(predicate, u => new UserSimpleInfo
        {
            Id = u.Id,
            Name = u.Name,
            Account = u.Account,
            OrgId = u.OrgId,
            WorkId = u.WorkId
        });
    }
    #region

    /// <summary>
    /// 检查输入
    /// </summary>
    /// <param name="user"></param>
    /// <returns></returns>
    private async Task CheckInput(SysUser user)
    {
        //检查部门是否存在
        if (!await _orgService.IsOrgExist(user.OrgId))
        {
            throw Oops.Bah(UserErrorCode.U010);
        }

        //判断帐号是否重复
        if (await IsAnyAsync(u => u.Account == user.Account && u.Id !=user.Id ))
        {
            throw Oops.Bah(UserErrorCode.U001);
        }
    }

    /// <summary>
    /// 检查导入数据
    /// </summary>
    /// <param name="importData"></param>
    /// <returns></returns>
    private async Task<(List<SysUser>, List<UserBatchAddOutput>)> CheckImportData(List<UserBatchAdd> importData)
    {
        if (importData.Count == 0)
        {
            throw Oops.Bah(UserErrorCode.U014);
        }
        var accountList=importData.Select(u=>u.Account.Trim()).ToList();//导入账号
        var users = await GetFieldListAsync(u => true,
            u => new SysUser
            {
                Id = u.Id,
                Name = u.Name,
                Account = u.Account,
                OrgId = u.OrgId,
                PositionId = u.PositionId,
                WorkId = u.WorkId,
                Phone = u.Phone
            });
        var sysOrgs = await _orgService.GetOrgList();         
        ConcurrentBag<UserBatchAddOutput> errorList = new();
        ConcurrentBag<SysUser> userList = new();
        // 检查导入数据中账号是否重复
        var repeatAccountList = importData.GroupBy(u => u.Account).
            Where(u => u.Count() > 1).
            Select(u=>u.Key).ToArray();
        // 检查导入数据中手机号是否重复
        var repeatPhoneList = importData.GroupBy(u => u.Phone).
            Where(u => u.Count() > 1).
            Select(u => u.Key).ToArray();
        var defaultPwd = await GetDefaultPassword();
        Parallel.ForEach(importData, item =>
        {
            var errorMessage = string.Empty;
            var res = item.TryValidate();//通过实体验证
            foreach (var error in res.ValidationResults)
            {
                errorMessage += error.ErrorMessage + ";";
            }
            if (repeatAccountList.Contains(item.Account))
            {
                errorMessage += "账号重复;";
            }
            if (users.Any(u => u.Account == item.Account))
            {
                errorMessage += "系统中已有该账号;";
            }
            if (repeatPhoneList.Contains(item.Phone))
            {
                errorMessage += "手机号重复;";
            }
            if (users.Any(u => u.Phone == item.Phone))
            {
                errorMessage += "系统中已有该手机号;";
            }

            if (!sysOrgs.Any(o => o.LongName == item.OrgName.Replace(" ", "")))
            {
                errorMessage += "系统中不存在该组织;";
            }
            //检查是否有该组织权限

            if (!string.IsNullOrEmpty(errorMessage))
            {
                var errorItem = item.Adapt<UserBatchAddOutput>();
                errorItem.ErrorMessages = errorMessage;
                errorList.Add(errorItem);
            }
            else
            {
                var user = item.Adapt<SysUser>();
                user.Id = Yitter.IdGenerator.YitIdHelper.NextId();
                user.OrgId = sysOrgs.FirstOrDefault(o => o.LongName == item.OrgName).Id;
                user.Password = defaultPwd;
                user.CreateTime = DateTime.Now;
                user.Gender = string.IsNullOrWhiteSpace(item.Gender) ? "other" : item.Gender;
                userList.Add(user);
            }
        });
        return (userList.ToList(), errorList.ToList());
    }

    /// <summary>
    /// 获取用户角色菜单列表
    /// </summary>
    /// <param name="userId"></param>
    /// <returns></returns>
    private async Task<List<MenuInfo>> GetUserRoleMenu()
    {
        var roleList = await _roleService.GetUserRoleList(UserManager.UserId);
        roleList.AddRange(await _roleService.GetUserRoleListByUserOrgId(UserManager.OrgId));
        List<MenuSimpleInfo> menuList = new();
        List<SysRelation> relationList = new();
        //如果是超管，那么直接获取所有菜单列表
        if (roleList.Any(r => r.Code == RoleConst.SUPERADMIN))
        {
            menuList = await _menuService.GetMenuList();
        }
        else
        {
            if (roleList.Count > 0)
            {
                //角色对应菜单
                relationList = await _relationService.GetRelationListByObjectIdList(CategoryConst.RELATION_ROLE_MENU,
                    roleList.Select(r => r.Id).Distinct().ToList());
                //菜单信息
                menuList = await _menuService.GetMenuListByMenuId(relationList.Select(r => r.TargetId).Distinct().ToList());
            }            
            var commonRoleMenu = await _roleService.GetCommonRoleMenu();//公共角色菜单
            menuList.AddRange(commonRoleMenu);
            menuList = menuList
                .GroupBy(item => item.Id)
                .Select(group => group.First())
                .OrderBy(item => item.SortCode)
                .ToList();
        }
        if (menuList.Count == 0) return [];
        List<MenuInfo> menuInfos = [];
        foreach(var menu in menuList)
        {
            var menuInfo = menu.Adapt<MenuInfo>();
            var meta = menu.Adapt<MenuMeta>();
            menuInfo.Meta = meta;
            menuInfos.Add(menuInfo);
        }
        return menuInfos;
    }

    /// <summary>
    /// 删除用户缓存
    /// </summary>
    /// <param name="userId"></param>
    private void DeleteUserCache(long userId)
    {
        _redisManager.HashDel<SysUser>(CacheConst.SysUser, userId.ToString());
    }

    private void DeleteUserCache(List<long> userIdList)
    {
        if (userIdList.Count == 0) return;
        var idArray = userIdList.Select(it => it.ToString()).ToArray();
        _redisManager.HashDel<SysUser>(CacheConst.SysUser, idArray);
    }

    private void RemoveApiRoleCache(long userId)
    {
        _redisManager.Remove(CacheConst.ApiRole+ userId);
    }
    #endregion
}